# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Resolvers::VulnerabilitySeveritiesCountResolver do
  include GraphqlHelpers

  describe '#resolve' do
    subject { resolve(described_class, obj: vulnerable, args: filters, ctx: { current_user: current_user }) }

    let_it_be(:project) { create(:project, :security_and_compliance_enabled) }
    let_it_be(:cluster_agent) { create(:cluster_agent, project: project) }
    let_it_be(:user) { create(:user, security_dashboard_projects: [project]) }

    let_it_be(:low_vulnerability) do
      create(:vulnerability, :with_findings, :detected, :low, :dast, project: project)
    end

    let_it_be(:medium_vulnerability) do
      create(:vulnerability, :with_cluster_image_scanning_finding, :detected, :medium, project: project, agent_id: cluster_agent.id)
    end

    let_it_be(:critical_vulnerability) do
      create(:vulnerability, :with_findings, :detected, :critical, :sast, project: project)
    end

    let_it_be(:high_vulnerability) do
      create(:vulnerability, :with_findings, :dismissed, :high, :container_scanning, :with_issue_links, resolved_on_default_branch: true, project: project)
    end

    let(:current_user) { user }
    let(:filters) { {} }
    let(:vulnerable) { project }

    context 'when the user does not have access' do
      it 'is redacted' do
        is_expected.to be_nil
      end
    end

    context 'when the user has access' do
      before do
        stub_licensed_features(security_dashboard: true)
        project.add_developer(current_user)
      end

      context 'when given severities' do
        let(:filters) { { severity: ['low'] } }

        it 'only returns count for low severity vulnerability' do
          is_expected.to eq('low' => 1)
        end
      end

      context 'when given states' do
        let(:filters) { { state: ['dismissed'] } }

        it 'only returns count for high severity vulnerability' do
          is_expected.to eq('high' => 1)
        end
      end

      context 'when given scanner' do
        let(:filters) { { scanner: [high_vulnerability.finding_scanner_external_id] } }

        it 'only returns count for high severity vulnerability' do
          is_expected.to eq('high' => 1)
        end
      end

      context 'when given image' do
        let(:filters) { { image: [medium_vulnerability.finding.image] } }

        it 'only returns count for medium severity vulnerability' do
          is_expected.to eq('medium' => 1)
        end
      end

      context 'when given cluster agent id' do
        let(:filters) { { cluster_agent_id: [cluster_agent.to_global_id.to_s] } }

        it 'only returns count for medium severity vulnerability' do
          is_expected.to eq('medium' => 1)
        end
      end

      context 'when given scanner ID' do
        let(:filters) { { scanner_id: [GitlabSchema.id_from_object(high_vulnerability.finding.scanner)] } }

        it 'only returns count for vulnerabilities with scanner ID' do
          is_expected.to eq('high' => 1)
        end
      end

      context 'when given report types' do
        let(:filters) { { report_type: %i[dast sast] } }

        it 'only returns count for vulnerabilities of the given report types' do
          is_expected.to eq('critical' => 1, 'low' => 1, 'medium' => 1)
        end
      end

      context 'when resolving vulnerabilities for a project' do
        it "returns the project's vulnerabilities" do
          is_expected.to eq('critical' => 1, 'high' => 1, 'low' => 1, 'medium' => 1)
        end
      end

      context 'when filtering vulnerabilities with issues' do
        let(:filters) { { has_issues: true } }

        it 'only returns count for vulnerabilities with issues' do
          is_expected.to eq('high' => 1)
        end
      end

      context 'when filtering vulnerabilities with issues' do
        let(:filters) { { has_issues: false } }

        it 'only returns count for vulnerabilities with issues' do
          is_expected.to eq('critical' => 1, 'low' => 1, 'medium' => 1)
        end
      end

      context 'when filtering resolved vulnerabilities' do
        let(:filters) { { has_resolution: true } }

        it 'only returns count for resolved vulnerabilities' do
          is_expected.to eq('high' => 1)
        end
      end

      context 'when filtering resolved vulnerabilities' do
        let(:filters) { { has_resolution: false } }

        it 'only returns count for resolved vulnerabilities' do
          is_expected.to eq('critical' => 1, 'low' => 1, 'medium' => 1)
        end
      end
    end

    context 'when resolving vulnerabilities for an instance security dashboard' do
      before do
        stub_licensed_features(security_dashboard: true)
        project.add_developer(user)
      end

      let(:vulnerable) { InstanceSecurityDashboard.new(current_user) }

      context 'when there is a current user' do
        it "returns vulnerabilities for all projects on the current user's instance security dashboard" do
          is_expected.to eq('critical' => 1, 'high' => 1, 'low' => 1, 'medium' => 1)
        end
      end

      context 'without a current user' do
        let(:current_user) { nil }

        it 'returns no vulnerabilities' do
          is_expected.to be_blank
        end
      end
    end
  end
end
